--Version history

	--1.12, 4/24 3:35PM, Billy's code merged with John's code and Dave's block diagram
-- Overall waveform test file generated
-- Overall block diagram created
-- PMLUT debugging needed.

	--1.11, 4/24 4:39AM, Unsigned math worked out
--now enters OuterLoop correctly, but not inner loop
--problems are delays in memory response...see simulation
--gate delays as well?

	--1.1, 4/21 7:30PM, Aging implemented
--explanation of aging:
--stamps are updated on write MAC, stamps are accessed on read MAC
--entries are expected to be stale
--if entries are >11 seconds apart, then will be stale
--only fresh, if entry was written to <11 seconds ago and accessed
--Status: compiles w/ 4 warnings, working on simulation

	--I/O
--inputs: Port SRC address, MAC SRC address, MAC DST address
--outputs: Port DST address, Broadcast
	--when Broadcast, Port DST is don't care

LIBRARY ieee;
USE ieee.std_logic_1164.all;
--USE ieee.numeric_std.all;
USE ieee.std_logic_arith.all;


ENTITY PMLUT_age IS
	PORT(	Port_SRC	:	IN	STD_LOGIC_VECTOR(1 DOWNTO 0);
			MAC_SRC		:	IN	STD_LOGIC_VECTOR(47 DOWNTO 0);
			MAC_DST		:	IN	STD_LOGIC_VECTOR(47 DOWNTO 0);
			clock		:	IN	STD_LOGIC;
			ReqLookUp	:	IN	STD_LOGIC;
			RESETN		:	IN 	STD_LOGIC;
		    PtrIN		: 	IN	STD_LOGIC_VECTOR (7 DOWNTO 0);
			VlanTag		:	IN	STD_LOGIC_VECTOR (31 DOWNTO 0);
			TagValid	:	IN	STD_LOGIC;
			FabricRdy	: 	IN  STD_LOGIC;
		 	LookUpRdy	: 	OUT STD_LOGIC;		
			
--!!!!!!!!!!!! some outputs disabled for testing
			Port_SRC_out:	OUT STD_LOGIC_VECTOR (1 DOWNTO 0);
			PtrOUT		: 	OUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			VlanTagOUT	:	OUT	STD_LOGIC_VECTOR (31 DOWNTO 0);
			TagValidOUT	:	OUT	STD_LOGIC ;
			Port_DST	:	OUT	STD_LOGIC_VECTOR(1 DOWNTO 0);
			BCAST		:	OUT	STD_LOGIC;
			
			--Testing outputs
			InnerLoop	:	OUT STD_LOGIC;
			OuterLoop	:	OUT STD_LOGIC;
			q_TimeStamp_left13bits	:	OUT STD_LOGIC_VECTOR(13 DOWNTO 0);
			q_MAC_right47bits		:	OUT STD_LOGIC_VECTOR(47 DOWNTO 0);
			qMemOut		:	OUT	STD_LOGIC_VECTOR(63 DOWNTO 0);	-- Billy's code
			Difference	:	OUT	UNSIGNED(13 DOWNTO 0)
		); 
END PMLUT_age;	 


ARCHITECTURE behavior of PMLUT_age is
	TYPE State_type IS (WaitForReq, BusyStart, ReadData, WriteData, WaitState); --possible states
	SIGNAL State : State_type;	
		--memory variables
	SIGNAL	data_memBlock		: STD_LOGIC_VECTOR (63 DOWNTO 0);
	SIGNAL	rdaddress_memBlock	: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL	rden_memBlock		: STD_LOGIC  := '1';	-- Billy's code
	SIGNAL	wraddress_memBlock	: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL	wren_memBlock		: STD_LOGIC  := '1';
	SIGNAL	q_memBlock			: STD_LOGIC_VECTOR (63 DOWNTO 0);
		--aging variables (assumes 50MHz clock)
	SHARED VARIABLE BigCounter	: UNSIGNED (13 DOWNTO 0);  --BigCounter rolls over ~1.018 days.
	SHARED VARIABLE SmallCounter : UNSIGNED (27 DOWNTO 0); --SmallCounter rolls over every ~5.369 seconds	
	SHARED VARIABLE TimeStamp	: STD_LOGIC_VECTOR (13 DOWNTO 0) := (OTHERS => '0');	
	CONSTANT FreshThresh	   	: UNSIGNED := "1100";   --Threshold for freshness is realtime ~10.74 seconds. 
														--For simulation purposes, will say it is 12 clock cycles
														--Based on BigCounter counts. 
		--test variables
	--SHARED VARIABLE InnerLoop	:	STD_LOGIC;
	--SHARED VARIABLE OuterLoop	:	STD_LOGIC;
	--SHARED VARIABLE Mem_TimeStamp	:	STD_LOGIC_VECTOR(13 DOWNTO 0);
	--SHARED VARIABLE Mem_MAC		:	STD_LOGIC_VECTOR(47 DOWNTO 0);
	
COMPONENT memBlock 
	PORT
	(
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (63 DOWNTO 0);
		rdaddress	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		rden		: IN STD_LOGIC  := '1';	-- Billy's code
		wraddress	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		wren		: IN STD_LOGIC  := '1';
		q			: OUT STD_LOGIC_VECTOR (63 DOWNTO 0)
	);
END COMPONENT;

	

BEGIN
	FSM_transitions:  PROCESS (RESETN, CLOCK)
	VARIABLE X1, X2 : INTEGER;
	
	BEGIN 	
		IF RESETN = '1' THEN
			
			State <= WaitForReq;   			    --If no request, Don't look up
			SmallCounter := (OTHERS => '0');	-- - Reset counters on RESET
			BigCounter := (OTHERS => '0');		-- /
		
		ELSIF(CLOCK'EVENT AND CLOCK = '1')THEN 
			
			--SmallCounter := SmallCounter+1;		--increase 28-bit counter by one
			SmallCounter := (OTHERS => '0');	--for debug, set to 0
			IF (SmallCounter = 0) 
				THEN BigCounter := BigCounter+1;--if 28-bit overflow, increment 14-bit counter
			END IF;
			
			CASE State IS 
			WHEN WaitForReq =>      
				wren_memBlock <= '0'; 
				rden_memBlock <= '0';	-- Billy's code        
				IF (ReqLookUp = '0' AND FabricRDY = '1') THEN
					State <= WaitForReq;
					LookUpRdy <= '1';
				ELSE 
					State <= BusyStart;  --After request set rdy bit low
					LookUpRdy <= '0';
				END IF;
				wren_memBlock <= '0';
				
			WHEN BusyStart =>
				State <= ReadData;
				--find address of Port_DST address by modding MAC_DST address
				X2 := CONV_INTEGER(UNSIGNED(MAC_DST)) mod 255;
				rdaddress_memBlock <= CONV_STD_LOGIC_VECTOR(X2, 8); 
				wren_memBlock <= '0';
				
			WHEN ReadData =>	
					rden_memBlock <= '1';	-- Billy's code			
				--if fresh value, then read Port_DST
					BCAST <= '1';			--default is to broadcast
					OuterLoop <= '0';
					InnerLoop <= '0';
					q_TimeStamp_left13bits <= q_memBlock(63 DOWNTO 50);
					q_MAC_right47bits <= q_memBlock(47 DOWNTO 0);
					Difference <= BigCounter-UNSIGNED(q_memBlock(63 DOWNTO 50)); --BigCounter - q_TimeStamp_left13bits
					qMemOut <= q_memBlock;	-- Billy's code
					IF (BigCounter - UNSIGNED(q_memBlock(63 DOWNTO 50))) < (FreshThresh) THEN  --if difference is < thresh, then broadcast 
						OuterLoop <= '1';
						IF q_memBlock(47 DOWNTO 0) = (MAC_DST) THEN
							InnerLoop <= '1';
							Port_DST <= q_memBlock(49 DOWNTO 48);
							BCAST <= '0';	--BCAST only off if entry fresh AND in LUT 
						END IF;
					END IF;	
					--IF q_memBlock(47 DOWNTO 0) = (MAC_DST) THEN
					--	Port_DST <= q_memBlock(49 DOWNTO 48);
					--	BCAST <= '0';
					--ELSE
					--	BCAST <= '1';
					--END IF;
					wren_memBlock <= '0';
--!!!!!!!!!!!!!!!!!! disabled for testing		
			PtrOUT		<= PtrIN;
			VlanTagOUT	<= VlanTag;
			TagValidOUT	<= TagValid;
			State 		<= WriteData;
				
			WHEN WriteData=>
				rden_memBlock <= '0'; 	-- Billy's code
				--convert MAC_SRC into address and write Port_SRC into that address
				X1 := CONV_INTEGER(UNSIGNED(MAC_SRC)) mod 255;
				wraddress_memBlock <= CONV_STD_LOGIC_VECTOR(X1, 8);
				TimeStamp := CONV_STD_LOGIC_VECTOR(BigCounter, 14);
				data_memBlock <= (TimeStamp & Port_SRC & MAC_SRC);
				wren_memBlock <= '1';
				
				IF FabricRdy = '1' THEN
					State <= WaitForReq;
					Port_SRC_out	<= Port_SRC;
					LookUpRdy <= '1';
				ELSE
					State <= WaitState;
					LookUpRdy <= '1';
				END IF;
				
			WHEN WaitState=>
				IF FabricRdy = '1' THEN
					State <= WaitforReq;
					Port_SRC_out	<= Port_SRC;
					LookUpRdy <= '1';
				ELSE
					State <= WaitState;
					LookUpRdy <= '1';
				END IF;
			END CASE;
			
		END IF; 
	END PROCESS;
	
	
MemoryAccess:  memBlock
	PORT MAP (clock, data_memBlock, rdaddress_memBlock, rden_memBlock,	-- Billy's code
	wraddress_memBlock, wren_memBlock, q_memBlock);
END Behavior; 	


LIBRARY ieee;
USE ieee.std_logic_1164.all;

LIBRARY altera_mf;
USE altera_mf.all;

ENTITY memBlock IS
	PORT
	(
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (63 DOWNTO 0);
		rdaddress	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		rden		: IN STD_LOGIC  := '1';	--Billy's code
		wraddress	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		wren		: IN STD_LOGIC  := '1';
		q			: OUT STD_LOGIC_VECTOR (63 DOWNTO 0)
	);
END memBlock;


ARCHITECTURE SYN OF memBlock IS

	SIGNAL sub_wire0	: STD_LOGIC_VECTOR (63 DOWNTO 0);

	COMPONENT altsyncram
	GENERIC (
		address_reg_b				: STRING;
		clock_enable_input_a		: STRING;
		clock_enable_input_b		: STRING;
		clock_enable_output_a		: STRING;
		clock_enable_output_b		: STRING;
		intended_device_family		: STRING;
		lpm_type					: STRING;
		numwords_a					: NATURAL;
		numwords_b					: NATURAL;
		operation_mode				: STRING;
		outdata_aclr_b				: STRING;
		outdata_reg_b				: STRING;
		power_up_uninitialized		: STRING;
		ram_block_type				: STRING;
		rdcontrol_reg_b				: STRING;
		read_during_write_mode_mixed_ports		: STRING;
		widthad_a					: NATURAL;
		widthad_b					: NATURAL;
		width_a						: NATURAL;
		width_b						: NATURAL;
		width_byteena_a				: NATURAL
	);
	PORT (
			wren_a		: IN STD_LOGIC ;
			clock0		: IN STD_LOGIC ;
			address_a	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
			address_b	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
			rden_b		: IN STD_LOGIC ;
			q_b			: OUT STD_LOGIC_VECTOR (63 DOWNTO 0);
			data_a		: IN STD_LOGIC_VECTOR (63 DOWNTO 0)
	);
	END COMPONENT;


BEGIN
	q    <= sub_wire0(63 DOWNTO 0);

	altsyncram_component : altsyncram
	GENERIC MAP (
		address_reg_b => "CLOCK0",
		clock_enable_input_a => "BYPASS",
		clock_enable_input_b => "BYPASS",
		clock_enable_output_a => "BYPASS",
		clock_enable_output_b => "BYPASS",
		intended_device_family => "Cyclone II",
		lpm_type => "altsyncram",
		numwords_a => 256,
		numwords_b => 256,
		operation_mode => "DUAL_PORT",
		outdata_aclr_b => "NONE",
		outdata_reg_b => "CLOCK0",
		power_up_uninitialized => "FALSE",
		ram_block_type => "M4K",
		rdcontrol_reg_b => "CLOCK0",	-- Billy's code
		read_during_write_mode_mixed_ports => "DONT_CARE",
		widthad_a => 8,
		widthad_b => 8,
		width_a => 64,
		width_b => 64,
		width_byteena_a => 1
	)
	PORT MAP (
		wren_a => wren,
		clock0 => clock,
		address_a => wraddress,
		address_b => rdaddress,
		rden_b => rden,	-- Billy's code
		data_a => data,
		q_b => sub_wire0
	);

END SYN;
